/*
 * GClubWLHistoryRecord.java
 * Created on 7 déc. 2008
 *
 * Glacéo Internet Platform
 * http://sourceforge.net/projects/chm/
 *
 * Copyright (c) 2005-2009, Jens and Jan Janke (VirtualHockey Project)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hockeo.vhbase.data.dao.club;


import java.math.BigDecimal;
import java.math.RoundingMode;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

import com.hockeo.vhbase.data.dao.IGEntity;
import com.hockeo.vhbase.data.dao.contest.GContestRound;
import com.hockeo.vhbase.data.dao.match.GKOMatch;
import com.hockeo.vhbase.data.dao.season.GSeason;
import com.hockeo.vhbase.data.dao.standings.GECRStandings;
import com.hockeo.vhbase.data.dao.standings.GENRStandings;
import com.hockeo.vhbase.data.dao.standings.GStandings;
import com.hockeo.vhbase.data.helper.GClubMultiRoundContestStatus;
import com.hockeo.vhbase.data.helper.GContestRoundType;

/**
 * Records results of a club in World League season.
 *
 * @version $Id$
 * @author jjanke
 */
@Entity
@DiscriminatorValue( "WL" )
public class GClubWLHistoryRecord extends GClubAbstractIntCupHistoryRecord
{
  /**
   * Constructs a new GClubWLHistoryRecord.
   *
   * @param season the season for which to create the record
   * @param club the club to attache to the created record
   * @param round the (cup) round to which the club is initially assigned
   * @param nSeeding the seeding rank of the club for which this history record is created
   */
  public GClubWLHistoryRecord( GSeason season, GClub club, GContestRound round, int nSeeding )
  {
    super( season, club, round, nSeeding );
  }

  /** Default parameterless constructor. */
  protected GClubWLHistoryRecord()
  {}

  /**
   * <p>
   * Calculates the current ECR point value based on the number of played rounds, matches,
   * reached points etc. and sets the calculated value to the super class using the method
   * {@link #setPointsECR(BigDecimal)}.
   * </p>
   *
   * <p>
   * ECR points for the World League are calculated as follows:
   * </p>
   *
   * <ol>
   * <li>The total number of reached points is determined. For one KO round a maximum of 6
   * points is awarded even if three matches are played. I.e. a team winning the round in
   * three matches with two wins and one defeat earns 4 out of 6 possible points. A team
   * winning the round with two straight wins earns 6 out of 6 points.</li>
   * <li>Points reached in qualification rounds are halved.</li>
   * <li>Bonus points are awarded according to the list below.</li>
   * <li>All reached points are added and then divided by the maximum possible amount of
   * points. The maximum includes all potentially obtainable bonus points. The potentially
   * reachable amount is calculated as from the round, a team has entered the competition.
   * I.e. a team entering the competition in the first round can reach less points then a
   * team entering the competition in the qualification round.</li>
   * <li>The quotient of the reached/possible points is then multiplied with the WL
   * competition coefficient. The result is the number of ECR points awarded for one WL
   * season.</li>
   * </ol>
   *
   * <p>
   * Bonus points
   * </p>
   * <ol>
   * <li>Qualified for the qualification round: 1 pt.</li>
   * <li>Qualification for the main round: 1 pt.</li>
   * <li>Qualification for the intermediate round: 1 pt.</li>
   * <li>Qualification for the quarter-final: 1 pt.</li>
   * <li>Qualification for the semi-final: 1 pt.</li>
   * <li>Finished 1st: 2 pts.</li>
   * <li>Finished 2nd: 1 pts.</li>
   * </ol>
   *
   * <p>
   * Maximum number of points:
   * </p>
   * <ol>
   * <li>Incl. qualification: 51 + bonus of 7 pts. = 58 pts.</li>
   * <li>W/o qualification: 48 + bonus of 6 pts. = 54 pts.</li>
   * </ol>
   *
   * @see GClubAbstractIntCupHistoryRecord#updateECRPoints(GContestRound, GKOMatch,
   *      GStandings, boolean)
   */
  @Override
  protected void updateECRPoints( final GContestRound roundLastAdded, final GKOMatch komatch,
      final GStandings standings, final boolean fRemove )
  {
    final int nSign = fRemove ? -1 : 1;

    switch ( roundLastAdded.getRoundType() )
    {
      case QUALIFICATION_1:
      {
        assert komatch != null;

        if ( fRemove )
        {
          d_decECRBasePoints = new BigDecimal( "0.00" );
          d_nECRBonusPoints = 0;
          break;
        }

        d_decECRBasePoints = BigDecimal.valueOf( komatch.getNumECRPoints( getClub() ).doubleValue() / 2.0 ).setScale(
            2, RoundingMode.HALF_UP );

        // All clubs qualified receive one bonus point
        //
        d_nECRBonusPoints += nSign * 1;

        break;
      }
      case ROUND_MAIN:
      {
        assert standings != null;

        if ( fRemove && !hasPlayedQuali() )
        {
          d_decECRBasePoints = new BigDecimal( "0.00" );
          d_nECRBonusPoints = 0;
          break;
        }

        d_decECRBasePoints = d_decECRBasePoints.add( BigDecimal.valueOf( nSign * standings.getNumPoints() ) );
        d_nECRBonusPoints += nSign * 1;

        break;
      }
      case ROUND_INTERMEDIATE:
      {
        assert standings != null;

        d_decECRBasePoints = d_decECRBasePoints.add( BigDecimal.valueOf( nSign * standings.getNumPoints() ) );
        d_nECRBonusPoints += nSign * 1;

        break;
      }
      case QUARTER_FINAL:
      case SEMI_FINAL:
      {
        assert komatch != null;

        d_decECRBasePoints = d_decECRBasePoints.add( komatch.getNumECRPoints( getClub() ).multiply(
            BigDecimal.valueOf( nSign ) ) );

        d_nECRBonusPoints += nSign * 1;

        break;
      }
      case FINAL:
      {
        assert komatch != null;

        d_decECRBasePoints = d_decECRBasePoints.add( komatch.getNumECRPoints( getClub() ).multiply(
            BigDecimal.valueOf( nSign ) ) );

        if ( komatch.isWinner( getClub() ) )
          d_nECRBonusPoints += nSign * 2;
        else
          d_nECRBonusPoints += nSign * 1;

        break;
      }

      default:
        throw new IllegalStateException( "Unsupported WL round type " + roundLastAdded.getRoundType().name() );
    }

    int nMaxECRPoints = 18 + 12 + 3 * 6 + 1 + 1 + 1 + 1 + 2;
    if ( hasPlayedQuali() )
      nMaxECRPoints += 3 + 1;

    BigDecimal decECR = d_decECRBasePoints.add( BigDecimal.valueOf( d_nECRBonusPoints ) ).divide(
        BigDecimal.valueOf( nMaxECRPoints ), RoundingMode.HALF_UP );

    setPointsECR( decECR.multiply( getContest().getRankingCoefficient() ).setScale( 2, RoundingMode.HALF_UP ) );
  }

  /*
   * @see com.hockeo.vhbase.data.dao.club.GClubHistoryRecord#getMultiRoundContestStatus()
   */
  @Override
  public GClubMultiRoundContestStatus getMultiRoundContestStatus()
  {
    if ( getReachedRound() == GContestRoundType.WINNER )
      return GClubMultiRoundContestStatus.FINISHED_FIRST;

    if ( getRank() > 0 )
      if ( getReachedRound() == GContestRoundType.FINAL )
        return GClubMultiRoundContestStatus.REACHED_LAST_ROUND;
      else
        return GClubMultiRoundContestStatus.ELIMINATED;

    return GClubMultiRoundContestStatus.QUALIFIED;
  }

  /*
   * @see com.hockeo.vhbase.data.dao.club.GClubHistoryRecord#updateECRStandings(com.hockeo.vhbase.data.dao.standings.GECRStandings)
   */
  @Override
  public void updateECRStandings( GECRStandings ecr )
  {
    ecr.setPointsS1EU2( getPointsECR() );
  }

  /*
   * @see com.hockeo.vhbase.data.dao.club.GClubHistoryRecord#updateENRStandings(com.hockeo.vhbase.data.dao.standings.GENRStandings)
   */
  @Override
  public void updateENRStandings( GENRStandings enr )
  {
    enr.addPoints( getClub(), getPointsECR() );
  }

  /*
   * @see com.hockeo.vhbase.data.dao.IGEntity#getGEntityClass()
   */
  public Class<? extends IGEntity> getGEntityClass()
  {
    return GClubWLHistoryRecord.class;
  }
}
